using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace AntsMap
{
    public class SolverBrute : Solver
    {
        //
        // The Brute Solver is horrendous.  Could be way more efficient (randomly finds next candidate)
        //


        private ArrayList blacklist;
        private int maxiter;

        public SolverBrute(int[,] soln, int dim, int elem, CostMap map, int iter )
        {
            solution = soln;
            prevsol = soln;
            dimensions = dim;
            elements = elem;
            blacklist = new ArrayList();
            Optimal = false;
            costmap = map;
            bestcost = 1000000000; //TODO fix that silly
            maxiter = iter;
        }

        private string SolutionAsString(int[,] soln)
        {
            string solstring = null;
            for (int i = 0; i < elements; i++)
            {
                for (int j = 0; j < dimensions; j++)
                {
                    solstring += soln[i, j].ToString();
                }
            }
            return solstring;
        }



        private bool SlotAvailable(int col, int index)
        {
            for (int i = 0; i < this.elements; i++)
            {
                if (this.solution[i, col] == index)
                    return false;
            }

            return true;
        }

        private int[,] GenerateSolution()
        {
           for (int i = 0; i < elements; i++)
                for (int j = 0; j < dimensions; j++)
                    solution[i, j] = -1;


            Random r = new Random();
            for (int i = 0; i < this.elements; i++)
            {
                for (int j = 0; j < this.dimensions; j++)
                {
                    if (i == 0)
                        this.solution[i, j] = r.Next(0, this.elements);
                    else
                    {
                        int index = r.Next(0, this.elements);
                        while (SlotAvailable(j, index) == false)
                        {
                            index = r.Next(0, this.elements);
                        }
                        this.solution[i, j] = index;
                    }
                }
            }
            return this.solution;
        }


        private int Factorial(int i)
        {
            return ((i <= 1) ? 1 : (i * Factorial(i - 1)));
        }


        public override int[,] SolveStep( )
        {
            solution = GenerateSolution();
            
            while (blacklist.Contains(SolutionAsString(solution)) == true)
            {
                solution = GenerateSolution();
            }
            blacklist.Add(SolutionAsString(solution));

            
            //if (blacklist.Count == Math.Pow(elements, dimensions+1))
            if ((blacklist.Count == Math.Pow( Factorial(costmap.Elements),costmap.Dimension)) || blacklist.Count == maxiter)
                Optimal = true;

            int thiscost = costmap.Cost(solution);
            if (thiscost < bestcost)
            {
                bestsol = solution;
                bestcost = thiscost;
            }
            prevsol = solution;
            return solution;
        }

        public override string Message()
        {
            return "Blacklist count: " + blacklist.Count.ToString();
        }

        public override int[,] BestSolution()
        {
            return bestsol;
        }

        public override int BestCost()
        {
            return bestcost;
        }
    }
}
